package com.example.service;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 缓存指标收集器
 * 负责收集和统计缓存使用情况的指标，包括命中率、加载时间等
 */
@Component
@Slf4j
public class CacheMetricsCollector {
    // 全局缓存访问计数器
    private final AtomicLong totalRequests = new AtomicLong(0);
    private final AtomicLong cacheHits = new AtomicLong(0);
    private final AtomicLong cacheMisses = new AtomicLong(0);
    
    // 数据库请求计数器
    private final AtomicLong databaseQueries = new AtomicLong(0);
    
    // 连接级别的命中率统计
    private final Map<Long, CacheStats> connectionStats = new ConcurrentHashMap<>();
    
    // 记录每小时的历史统计数据（保留最近24小时）
    private final Map<String, HistoricalStats> hourlyStats = new ConcurrentHashMap<>();
    
    // 应用启动时间
    private final long startTime = System.currentTimeMillis();
    
    /**
     * 定时统计任务，每小时记录一次
     */
    @Scheduled(cron = "0 0 * * * *") // 每小时整点执行
    public void recordHourlyStats() {
        double hitRate = totalRequests.get() > 0 
                ? (double) cacheHits.get() / totalRequests.get() : 0;
        
        String hourKey = String.format("%tF %tH:00", System.currentTimeMillis(), System.currentTimeMillis());
        
        HistoricalStats stats = new HistoricalStats();
        stats.setTimestamp(System.currentTimeMillis());
        stats.setTotalRequests(totalRequests.get());
        stats.setCacheHits(cacheHits.get());
        stats.setCacheMisses(cacheMisses.get());
        stats.setHitRate(hitRate);
        stats.setDatabaseQueries(databaseQueries.get());
        
        hourlyStats.put(hourKey, stats);
        
        // 只保留最近24小时的数据
        if (hourlyStats.size() > 24) {
            String oldest = hourlyStats.keySet().stream()
                    .sorted()
                    .findFirst()
                    .orElse(null);
            if (oldest != null) {
                hourlyStats.remove(oldest);
            }
        }
        
        log.info("记录缓存小时统计：时间={}, 命中率={}%, 总请求={}",
                hourKey,
                String.format("%.2f", hitRate * 100),
                totalRequests.get());
    }
    
    /**
     * 定时输出日志，每天执行一次
     */
    @Scheduled(cron = "0 0 0 * * *") // 每天0点执行
    public void logDailyCacheMetrics() {
        double hitRate = totalRequests.get() > 0 
                ? (double) cacheHits.get() / totalRequests.get() : 0;
        
        log.info("缓存性能每日统计：总请求={}, 命中={}, 未命中={}, 命中率={}%, 数据库查询={}",
                totalRequests.get(),
                cacheHits.get(),
                cacheMisses.get(),
                String.format("%.2f", hitRate * 100),
                databaseQueries.get());
                
        // 连接级别统计
        connectionStats.forEach((connId, stats) -> {
            if (stats.getTotalRequests() > 0) {
                log.info("连接{}缓存统计: 总请求={}, 命中率={}%, 平均加载时间={}ms",
                        connId,
                        stats.getTotalRequests(),
                        String.format("%.2f", stats.getHitRate() * 100),
                        stats.getAverageLoadTime());
            }
        });
    }
    
    /**
     * 记录缓存访问
     * @param connectionId 连接ID
     * @param isHit 是否命中缓存
     * @param loadTimeMs 加载时间(毫秒)
     */
    public void recordCacheAccess(Long connectionId, boolean isHit, long loadTimeMs) {
        totalRequests.incrementAndGet();
        
        if (isHit) {
            cacheHits.incrementAndGet();
        } else {
            cacheMisses.incrementAndGet();
            databaseQueries.incrementAndGet();
        }
        
        // 更新连接级别统计
        connectionStats.computeIfAbsent(connectionId, k -> new CacheStats())
                .recordAccess(isHit, loadTimeMs);
    }
    
    /**
     * 获取当前缓存统计信息
     */
    public Map<String, Object> getCurrentStats() {
        Map<String, Object> stats = new HashMap<>();
        
        double hitRate = totalRequests.get() > 0 
                ? (double) cacheHits.get() / totalRequests.get() : 0;
        
        stats.put("totalRequests", totalRequests.get());
        stats.put("cacheHits", cacheHits.get());
        stats.put("cacheMisses", cacheMisses.get());
        stats.put("hitRate", hitRate);
        stats.put("databaseQueries", databaseQueries.get());
        stats.put("uptimeMs", System.currentTimeMillis() - startTime);
        
        // 连接级别统计
        Map<String, Object> connStats = connectionStats.entrySet().stream()
                .filter(e -> e.getValue().getTotalRequests() > 0)
                .collect(Collectors.toMap(
                        e -> e.getKey().toString(),
                        e -> {
                            Map<String, Object> connStat = new HashMap<>();
                            connStat.put("totalRequests", e.getValue().getTotalRequests());
                            connStat.put("hits", e.getValue().getHits());
                            connStat.put("hitRate", e.getValue().getHitRate());
                            connStat.put("avgLoadTime", e.getValue().getAverageLoadTime());
                            return connStat;
                        }
                ));
        
        stats.put("connectionStats", connStats);
        
        // 历史统计
        stats.put("hourlyStats", hourlyStats);
        
        return stats;
    }
    
    /**
     * 获取当前命中率
     */
    public double getCurrentHitRate() {
        return totalRequests.get() > 0 
                ? (double) cacheHits.get() / totalRequests.get() 
                : 0;
    }
    
    /**
     * 清除统计
     */
    public void resetStats() {
        totalRequests.set(0);
        cacheHits.set(0);
        cacheMisses.set(0);
        databaseQueries.set(0);
        connectionStats.clear();
        // 保留历史数据
    }
    
    /**
     * 内部类：连接级别缓存统计
     */
    @Data
    public static class CacheStats {
        private long totalRequests = 0;
        private long hits = 0;
        private long totalLoadTimeMs = 0;
        private long loadCount = 0;
        
        public void recordAccess(boolean isHit, long loadTimeMs) {
            totalRequests++;
            if (isHit) {
                hits++;
            } else {
                totalLoadTimeMs += loadTimeMs;
                loadCount++;
            }
        }
        
        public double getHitRate() {
            return totalRequests > 0 ? (double) hits / totalRequests : 0;
        }
        
        public long getAverageLoadTime() {
            return loadCount > 0 ? totalLoadTimeMs / loadCount : 0;
        }
    }
    
    /**
     * 内部类：历史统计数据
     */
    @Data
    public static class HistoricalStats {
        private long timestamp;
        private long totalRequests;
        private long cacheHits;
        private long cacheMisses;
        private double hitRate;
        private long databaseQueries;
    }
} 